﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;

namespace UtilZ.Dotnet.Ex.Log
{
    /// <summary>
    /// 文件日志追加器
    /// </summary>
    public class FileAppender : AppenderAbs
    {
        /// <summary>
        /// 左斜杠'\\'
        /// </summary>
        public static readonly char LeftSlash = '\\';

        /// <summary>
        /// 右斜杠 '/'
        /// </summary>
        public static readonly char RightSlash = '/';

        /// <summary>
        /// 路径斜杠
        /// </summary>
        public static readonly char PathSlash;


        static FileAppender()
        {
            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.Win32NT:
                case PlatformID.Win32S:
                case PlatformID.Win32Windows:
                    PathSlash = RightSlash;
                    break;
                case PlatformID.Unix:
                case PlatformID.MacOSX:
                default:
                    PathSlash = LeftSlash;
                    break;
            }
        }



        private LogWriteMode _writeMode;
        private PrimitiveFileAppender _mergeFileAppender = null;
        private Dictionary<LogLevel, PrimitiveFileAppender> _separateFileAppenderDic = null;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ele">配置元素</param>
        public FileAppender(XElement ele) : base(ele)
        {
            this.Init();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="config">配置对象</param>
        public FileAppender(FileAppenderConfig config) : base(config)
        {
            this.Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            var fileAppenderConfig = (FileAppenderConfig)base._config;
            this._writeMode = fileAppenderConfig.WriteMode;

            if (fileAppenderConfig.WriteMode == LogWriteMode.Merge)
            {
                this._mergeFileAppender = new PrimitiveFileAppender(fileAppenderConfig);
            }
            else
            {
                this._separateFileAppenderDic = new Dictionary<LogLevel, PrimitiveFileAppender>();
                FileAppenderConfig tempConfig;

                if (fileAppenderConfig.Levels == null || fileAppenderConfig.Levels.Length <= 0)
                {
                    //所有日志级别全部记录
                    tempConfig = CopyConfig(fileAppenderConfig, LogLevel.Trace);
                    this._separateFileAppenderDic.Add(LogLevel.Trace, new PrimitiveFileAppender(tempConfig));

                    tempConfig = CopyConfig(fileAppenderConfig, LogLevel.Debug);
                    this._separateFileAppenderDic.Add(LogLevel.Debug, new PrimitiveFileAppender(tempConfig));

                    tempConfig = CopyConfig(fileAppenderConfig, LogLevel.Info);
                    this._separateFileAppenderDic.Add(LogLevel.Info, new PrimitiveFileAppender(tempConfig));

                    tempConfig = CopyConfig(fileAppenderConfig, LogLevel.Warn);
                    this._separateFileAppenderDic.Add(LogLevel.Warn, new PrimitiveFileAppender(tempConfig));

                    tempConfig = CopyConfig(fileAppenderConfig, LogLevel.Error);
                    this._separateFileAppenderDic.Add(LogLevel.Error, new PrimitiveFileAppender(tempConfig));

                    tempConfig = CopyConfig(fileAppenderConfig, LogLevel.Fatal);
                    this._separateFileAppenderDic.Add(LogLevel.Fatal, new PrimitiveFileAppender(tempConfig));
                }
                else
                {
                    //只记录指定日志级别的日志
                    foreach (var level in fileAppenderConfig.Levels)
                    {
                        tempConfig = CopyConfig(fileAppenderConfig, level);
                        this._separateFileAppenderDic.Add(level, new PrimitiveFileAppender(tempConfig));
                    }
                }
            }
        }

        private static FileAppenderConfig CopyConfig(FileAppenderConfig fileAppenderConfig, LogLevel level)
        {
            string levelStr = level.ToString();
            var tempConfig = new FileAppenderConfig()
            {
                AppenderName = $"{fileAppenderConfig.AppenderName}_{levelStr}",
                //Layout = fileAppenderConfig.Layout,
                DateFormat = fileAppenderConfig.DateFormat,
                LevelMap = fileAppenderConfig.LevelMap,
                SeparatorCount = fileAppenderConfig.SeparatorCount,
                EnableOutputCache = fileAppenderConfig.EnableOutputCache,

                Enable = fileAppenderConfig.Enable,
                Levels = fileAppenderConfig.Levels,
                EventIdMin = fileAppenderConfig.EventIdMin,
                EventIdMax = fileAppenderConfig.EventIdMax,
                MatchString = fileAppenderConfig.MatchString,
                //LevelMapDic=


                Days = fileAppenderConfig.Days,
                MaxFileCount = fileAppenderConfig.MaxFileCount,
                MaxFileSize = fileAppenderConfig.MaxFileSize,
                //FilePath =
                IsAppend = fileAppenderConfig.IsAppend,
                LockingModel = fileAppenderConfig.LockingModel,
                WriteMode = fileAppenderConfig.WriteMode,
            };

            tempConfig.SetLogLayout(fileAppenderConfig.Layout);
            tempConfig.LevelMapDic.Clear();
            foreach (var kv in fileAppenderConfig.LevelMapDic)
            {
                tempConfig.LevelMapDic.Add(kv.Key, kv.Value);
            }

            if (string.IsNullOrWhiteSpace(fileAppenderConfig.FilePath))
            {
                tempConfig.FilePath = $@"Log/{levelStr}/*yyyy-MM-dd_HH_mm_ss.fffffff*.log";
            }
            else
            {
                int index1 = fileAppenderConfig.FilePath.IndexOf(LeftSlash);
                int index2 = fileAppenderConfig.FilePath.IndexOf(RightSlash);
                int index = Math.Max(index1, index2);
                string path1, path2;
                if (index >= 0)
                {
                    path1 = fileAppenderConfig.FilePath.Substring(0, index);
                    path2 = fileAppenderConfig.FilePath.Substring(index + 1, fileAppenderConfig.FilePath.Length - index - 1);
                    tempConfig.FilePath = $"{path1}{PathSlash}{levelStr}/{path2}";
                }
                else
                {
                    tempConfig.FilePath = $@"{levelStr}{PathSlash}{fileAppenderConfig.FilePath}";
                }
            }

            return tempConfig;
        }


        /// <summary>
        /// 创建配置对象实例
        /// </summary>
        /// <param name="ele">配置元素</param>
        /// <returns>配置对象实例</returns>
        protected override BaseConfig CreateConfig(XElement ele)
        {
            return new FileAppenderConfig(ele);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="item">日志项</param>
        protected override void PrimitiveWriteLog(LogItem item)
        {
            try
            {
                if (this._writeMode == LogWriteMode.Merge)
                {
                    this._mergeFileAppender.WriteLog(item);
                }
                else
                {
                    PrimitiveFileAppender fileAppender;
                    if (this._separateFileAppenderDic.TryGetValue(item.Level, out fileAppender))
                    {
                        fileAppender.WriteLog(item);
                    }
                }
            }
            catch (Exception ex)
            {
                LogSysInnerLog.OnRaiseLog(this, ex);
            }
        }
    }
}
